# 用贪心算法求一个较优解
# 从权重最大的开始，尽可能多排，依次向下找
import PersonList1
import PersonWeightSort
import numpy as np
import copy

MyCount = 0
AllProbably = [] #用来记录所有可能的上班表
# 排班算法主要程序
def ScheduledAlgo():
    # 拿到所有人的计划
    #all_person = PersonList1.RandomFun(14)
    # 该表装载上班的映射矩阵
    scheduled_rule = []
    # 该表装载上班的映射矩阵
    scheduled_list = np.zeros((6,7),dtype=int)

    #print("all_person",all_person)
    # print("scheduled_list",scheduled_list)
    # 临时使用
    PersonWeight = [{0: [4, 1, 3, 1, 1, 2]}, {1: [2, 1, 4, 1, 1, 3]}, {2: [4, 1, 3, 1, 1, 2]}, {3: [3, 1, 2, 1, 3, 2]}, {4: [6, 1, 1, 1, 1, 2]}, {5: [5, 1, 1, 1, 1, 3]}, {6: [4, 2, 1, 1, 1, 3]}, {7: [1, 4, 2, 
2, 1, 2]}, {8: [1, 4, 1, 3, 1, 2]}, {9: [1, 1, 5, 2, 1, 2]}, {10: [5, 1, 1, 2, 1, 2]}, {11: [6, 1, 1, 1, 1, 2]}, {12: [5, 1, 1, 2, 1, 2]}, {13: [3, 1, 3, 2, 1, 2]}, {14: [3, 1, 3, 2, 1, 2]}, {15: [3, 1, 3, 2, 1, 2]}, {16: [3, 1, 3, 2, 1, 2]}]
    ScheduledWeight = PersonWeightSort.Mysort(PersonWeight) #对上面的上班喜好进行权重排序
    # 所有人可上班的天数列表
    PersonCount = [4]*18
    print("PersonCount",PersonCount)
    print("ScheduledWeight",ScheduledWeight)

    # 递归计算出所有上班的可能
    DiGuiAlgo(scheduled_list,1,ScheduledWeight)  #参数依次为：0的个数，当前的scheduled_list;每个id可上班的次数
    # global MyCount
    # print(scheduled_list)

def DiGuiAlgo(scheduled_list,deep,ScheduledWeight):
    # 为了保障值班的完整性，按天进行贪心算法，保障每个班都有人上
    # 因为都是列表，所以得在新的列表里面操作
    if deep > 7:
        return
        
    deep0 = deep
    scheduled_list0 = []
    scheduled_list0 = copy.deepcopy(scheduled_list)
    # 找权重最大的一个人上周一的第一个班
    for i in range(6):#6个班种
        for j in range(len(list(ScheduledWeight[i].values())[0])):#从当前班种里找一个权重最大的人出来上班
            if deep == 7:
                pass
                #print("j_______________________:",j,"人员id:",list(ScheduledWeight[i].values())[0][j])
            if MyCheck(scheduled_list0,list(ScheduledWeight[i].values())[0][j],deep,i):
                scheduled_list0[i,deep-1] = list(ScheduledWeight[i].values())[0][j]
                # print(i)
                # print(deep)
                # print(list(ScheduledWeight[i].values())[0][j])
                print(scheduled_list0)
                if np.sum(np.where(scheduled_list0,0,1)) == 0:
                    print("i:",i,"+++++++  deep:",deep)
                    print(scheduled_list0)
                break
    
    DiGuiAlgo(scheduled_list0,deep+1,ScheduledWeight)

# 检验将id为i+1的人放到scheduled_list表(42 - ZerosCount)位置是否合适
def MyCheck(scheduled_list,i,deep,WhichClass):
    # 统计当前0的个数
    ZerosCount = np.sum(np.where(scheduled_list[:,deep-1:deep],0,1))
    # i将要放到的位置，即第a行，第b列
    a = 6 - ZerosCount
    b = deep-1
    c = scheduled_list
    #检验这个人本周的上班次数是否超过4
    if np.sum(np.where(c-i,0,1)) > 3:
        return False
    #检验当天这个人是否已有上班
    for k in range(a):
        if scheduled_list[k,b] == i:#当天这个人已经上班了，就返回False
            return False
    #检验这个人前一天是否是航后
    if b >= 1 and (scheduled_list[2,b-1] == i or scheduled_list[3,b-1] == i):#当天这个人已经上班了，就返回False
        return False
    #检验这个人往前两天是否是夜班
    if b >= 2 and (scheduled_list[4,b-2] == i or scheduled_list[5,b-2] == i):#
        return False
    #检验夜班的次数不能大于1
    if (WhichClass == 4 or WhichClass == 5) and np.bincount(scheduled_list[4,:],minlength = i+1)[i] + np.bincount(scheduled_list[5,:],minlength = i+1)[i] > 0:#第五行、第6行的个数之和不能大于1
        return False
    return True


# 主函数
if __name__=="__main__":
    ScheduledAlgo()